package cz.muni.fi.pa165.travelagency.persistence;

import cz.muni.fi.pa165.travelagency.api.entities.IOrder;
import cz.muni.fi.pa165.travelagency.entities.Tour;
import java.util.Date;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 * Data access object for tours
 *
 * @author Petr Stribny
 * @created 16-10-2012
 * @version 1.0
 */
@Stateless
public class TourDAO implements ITourDAO {

    @PersistenceContext(unitName = "LivePU")
    private EntityManager em;

    void setEntityManager(EntityManager em) {
        this.em = em;
    }

    @Override
    public void createTour(Tour tour) {
        if (tour == null) {
            throw new IllegalArgumentException("Tour cannot be null.");
        }

        if (tour.getId() != null) {
            throw new IllegalStateException("Id has to be null.");
        }

        if (tour.getName() == null || tour.getName().isEmpty()) {
            throw new IllegalArgumentException("Name has to be set.");
        }

        if (tour.getAssociatedTour() == null) {
            throw new IllegalArgumentException("Associated tour has to be set.");
        }

        if (tour.getCapacity() <= 0) {
            throw new IllegalArgumentException("Capacity has to be greater than zero.");
        }

        if (tour.getPricePerPerson().intValue() <= 0) {
            throw new IllegalArgumentException("Price has to be greater than zero.");
        }

        if (tour.getDate() == null) {
            throw new IllegalArgumentException("Date has to be set.");
        }

        if (!tour.getDate().after(new Date())) {
            throw new IllegalArgumentException("Date has to be in the future!");
        }

        try {
            em.persist(tour);
        } catch (Exception e) {
            throw new DAOException(e.getMessage(), e);
        } 
    }

    @Override
    public void deleteTour(Tour tour) {
        if (tour == null) {
            throw new IllegalArgumentException("Tour cannot be null.");
        }

        if (tour.getId() == null) {
            throw new IllegalStateException("Id cannot be null.");
        }

        try {
            tour = em.merge(tour);
            List<IOrder> orders = tour.getOrders();
            for (IOrder o: orders) {
                o.getOrderedTours().remove(tour);
                em.merge(o);
            }
            
            em.remove(tour);
        } catch (Throwable t) {
            throw new DAOException(t.getMessage(), t);
        } 
    }

    @Override
    public int getAvailablePlaces(Tour tour) {
        if (tour == null) {
            throw new IllegalArgumentException("Tour cannot be null.");
        }

        if (tour.getId() == null) {
            throw new IllegalStateException("Id cannot be null.");
        }
        
        int count;
        try {
            Query query = em.createNativeQuery("SELECT SUM(NUMBEROFPERSONS) FROM ORDERS JOIN ORDERS_TOURS ON "
                    + "ORDERS.ID = ORDERS_TOURS.ORDERS_ID WHERE ORDERS_TOURS.TOUR_ID = :tour_id");
            query.setParameter("tour_id", tour.getId());
            if(query.getSingleResult() == null) {
                return 0;
            }
            count = (Integer) query.getSingleResult();
        } catch (NoResultException | NonUniqueResultException e) {
            return 0;
        }

        return tour.getCapacity() - count;
    }

    @Override
    public Tour getTour(Long id) {
        if (id == null) {
            throw new IllegalArgumentException("Id cannot be null.");
        }

        Tour tour = null;
        try {
            tour = em.find(Tour.class, id);
        } catch (Throwable t) {
            throw new DAOException(t.getMessage(), t);
        }    

        return tour;
    }

    @Override
    public void updateTour(Tour tour) {
        if (tour == null) {
            throw new IllegalArgumentException("Tour cannot be null.");
        }

        if (tour.getId() == null) {
            throw new IllegalStateException("Id cannot be null.");
        }

        if (tour.getName() == null || tour.getName().isEmpty()) {
            throw new IllegalArgumentException("Name has to be set.");
        }

        if (tour.getAssociatedTour() == null) {
            throw new IllegalArgumentException("Associated tour has to be set.");
        }

        if (tour.getCapacity() <= 0) {
            throw new IllegalArgumentException("Capacity has to be greater than zero.");
        }

        if (tour.getPricePerPerson().intValue() <= 0) {
            throw new IllegalArgumentException("Price has to be greater than zero.");
        }

        if (tour.getDate() == null) {
            throw new IllegalArgumentException("Date has to be set.");
        }

        if (!tour.getDate().after(new Date())) {
            throw new IllegalArgumentException("Date has to be in the future!");
        }

        try {
            em.merge(tour);
        } catch (Throwable t) {
            throw new DAOException(t.getMessage(), t);
        }
    }
}
